{
  LW Volume -- LightWave Volumetric Elements

  This header defines the volumetric rendering element..

  Based on lwvolume.h which is:
  Copyright 1999, NewTek, Inc.
}

{
  Copyright 2012, Jameel Halabi

  This unit is part of the BlaiseWave wrapper,
  which is licensed under the BSD 2-Clause license (see licenses/license.txt).
}

unit LW_Volume;

{$mode objfpc}{$H+}

interface

uses
  LW_Types   ,
  LW_Handler ,
  LW_Render  ;

const
  LWVOLUMETRIC_HCLASS	 = 'VolumetricHandler'   ;
  LWVOLUMETRIC_ICLASS	 = 'VolumetricInterface' ;
  LWVOLUMETRIC_GCLASS	 = 'VolumetricGizmo'     ;
  LWVOLUMETRIC_VERSION   = 7 ;

  LWVEF_OPACITY	    = 1 shl 0 ; // light attenuation is evaluated ( shadows )
  LWVEF_COLOR       = 1 shl 1 ; // light scattering is evaluated ( shading )
  LWVEF_RAYTRACE    = 1 shl 2 ; // raytracing context
  LWVEF_CAMERA      = 1 shl 3 ; // the ray originates from the camera
  LWVEF_RADIOSITY   = 1 shl 4 ; // the ray originates from radiosity
  LWVEF_SAMPLEDRAY  = 1 shl 5 ; // this flag is on if the incoming ray was cast for sampling soft reflections, etc.
  LWVEF_PREPROCESS  = 1 shl 6 ; // this flag is on if the incoming ray is a radiosity preprocess ray
  LWVEF_REFLECTION  = 1 shl 7 ; // this flag is on if the incoming ray is a reflection ray

  LWVOLF_SHADOWS      = 1 shl 0 ;  // element will be evaluated for shadows
  LWVOLF_REFLECTIONS  = 1 shl 1 ; // element will be evaluated for raytraced reflections
  LWVOLF_REFRACTIONS  = 1 shl 2 ; // element will be evaluated for raytraced refractions

  LWVRAYFUNCS_GLOBAL  =	'VRayFuncs 5' ;

  LWVOLUMETRICEVALUATIONFUNCS_GLOBAL = 'VolumetricEvaluationFuncs' ;

type
  { A volume sample is a single segment along a ray through a
  volmetric function that has a uniform color and opacity.  The
  dist and stride are the position and size of the sample and
  the opacity and color are given as color vectors. }

  PLWVolumeSample = ^TLWVolumeSample;
  TLWVolumeSample = record
    Dist    : 	Double		       ;
    Stride  :	Double		       ;
    Opacity :	array [0..2] of Double ;
    Color   :	array [0..2] of Double ;
  end;

  { Volumetric ray access structure is passed to the volume rendering
server to add its contribution to a ray passing through space.  The
ray is given by a void pointer.

    flags Evaluation flags.  Indicates whether color or opacity or
                             both should be computed.

    source Origin of ray.    Can be a light, the camera, or an object
                             (for surface rendering).

    o, dir                   Origin and direction of ray.

    rayColor		     Color that is viewed from the origin of the ray,
                             before volumetric effects are applied.

    far,near	             Far and near clipping distances.

    oDist	             Distance from origin
                             (>0 when raytracing reflections / refractions).

    frustum	             Pixel frustum.

    addSample	             Add a new volume sample to the ray.

    getOpacity	             Returns opacity (vector and scalar)
                             at specified distance.

    sx, sy	             The position of the pixel for which
                             the volumetric is being rendered.

    bounces	             The current number of ray recursion bounces.  }

    PLWVolumeAccess = ^TLWVolumeAccess ;
    TLWVolumeAccess = record
      Ray : Pointer ;
      Flags : Integer ;
      Source : PLWItem;

      O    ,
      Dir  ,
      RayColor : array [0..2] of Double;
      FarClip  ,
      NearClip ,
      ODist    ,
      Frustum  : Double ;

      AddSample  : procedure ( Ray : Pointer ; SMP : PLWVolumeSample ) ;
      GetOpacity : function (Ray : Pointer; Dist : Double ;  Opa  : array {[0..2]} of Double ) : Double;

      Illuminate : TLWIlluminateFunc ;
      RayTrace   : TLWRayTraceFunc   ;
      RayCast    : TLWRayCastFunc    ;
      RayShade   : TLWRayShadeFunc   ;

      SX         ,
      SY         : Double ;
      Bounces    : Integer ;

      RayTraceMode           : TLWRayTraceModeFunc          ;
      IlluminateSample       : TLWIlluminateSampleFunc      ;
      RandomData             : PRandomFloatData             ;
      RandomFloat            : TLWRandomFloatFunc           ;
      IlluminateNormal       : TLWIlluminateNormalFunc      ;
      IlluminateSampleNormal : TLWIlluminateSampleNormalFunc;

      RayTraceData           : TLWRayTraceDataFunc          ;
      RayTraceShade          : TLWRayTraceShadeFunc         ;
      Render                 : PLWRenderData                ;

      GetVal                 : TLWBufferGetValFunc          ;
      SetVal		     : TLWBufferSetValFunc          ;

      ShaderSamplerState     : PLWSamplerState              ;
      GetShaderSamplerRange  : TLWGetSamplerRangeFunc       ;
      GetShaderSample2D      : TLWGetSample2DFunc           ;
      GetShaderSample1D      : TLWGetSample1DFunc           ;
    end;

    PLWVolumetricHandler = ^TLWVolumetricHandler ;
    TLWVolumetricHandler = record
      Inst        : PLWInstanceFuncs;
      Item        : PLWItemFuncs    ;
      Rend        : PLWRenderFuncs  ;

      Evaluate    : function
                    (      Instance : PLWInstance       ;
                     const Access   : PLWVolumeAccess   ) : Double ;
      Flags       : function
                    (      Instance : PLWInstance       ) : UInt32 ;
    end;

    PLWVRayFuncs = ^TLWVRayFuncs ;
    TLWVRayFuncs = record
      // Create a new volume access structure, but does not initialize it.
      // However, the member values are not garbage; so it is possible to 'Destroy' it
      // without having 'Init'ialized it.
      New            : function
                       (  const Void                                   ) : PLWVolumeAccess;

      // Destroys an existing volume access structure
      Destroy        : function
                       (        Ray           : PLWVolumeAccess        ) : PLWError;

      // Initializes the ray
      Init           : procedure
                       (      Ray           : PLWVolumeAccess        ;   // Ray to initialize
      	                      O             ,                            // Ray source position (world coordinates)
      		       	      Dir           : array {[0..2]} of Double;   // Ray direction (world coordinates)
      	                      NearClip      ,                            // Near clipping plane distance
      	                      FarClip       : Double                 ;   // Far clipping plane distance
      	                      EvalFlag      ,                            // Evaluation flags
      	                      HRes          : Integer                ;   // Boolean (1 = use hfov; 0 = assume square)
      	                      HFOV          ,                            // Horizontal field of view
      	                      IncMultiplier : Double                 ;   // Frustrum multiplier (normally 1.0)
      	                      Illuminate    : TLWIlluminateFunc      ) ; // Illumination callback

      // Sets the render functions to be called when this ray is evaluated.
      SetRenderFuncs : procedure
                       (      Ray                    : PLWVolumeAccess               ;  // Ray to be adjusted
      	                      Illuminate             : TLWIlluminateFunc             ;  // Illumination callback
      	                      RayTrace               : TLWRayTraceFunc               ;  // Raytrace callback
      	                      RayCast                : TLWRayCastFunc                ;  // Raycast callback
      	                      RayShade               : TLWRayShadeFunc               ;  // Rayshade callback
      	                      RayTraceMode           : TLWRayTraceModeFunc           ;  // Raytracemode callback
      	                      IlluminateSample       : TLWIlluminateSampleFunc       ;  // Illumination sample callback
      	                      RandomFloat            : TLWRandomFloatFunc            ;  // RandomFloat function callback
      	                      IlluminateNormal       : TLWIlluminateNormalFunc       ;  // Normal testing illumination callback
      	                      IlluminateSampleNormal : TLWIlluminateSampleNormalFunc ;  // Normal testing illumination sample callback
      	                      RayTraceData           : TLWRayTraceDataFunc           ;  // Raytrace data function.
      	                      RayTraceShade          : TLWRayTraceShadeFunc          ;  // Raytrace shade function relies on the raytrace data.
      	                      GetShaderSamplerRange  : TLWGetSamplerRangeFunc        ;  // Sampler functions for evaluating shaders from within a volumetric plugin.
      	                      GetShaderSample2D      : TLWGetSample2DFunc            ;
      	                      GetShaderSample1D      : TLWGetSample1DFunc            ) ;

      /// Flattening a ray simpling combines all the volume samples contained and resolves
      /// them to a single color and opacity
      Flatten        : function
                       (      Ray                    : PLWVolumeAccess               ;  // Ray to be flattened
      	                      Color                  ,                                  // Resulting rgb color
      	                      Opa                    : array {[0..2]} of Double      ) : Double ;  // Resulting opacity for each color channel.
    end;

    { In order to get a volumetric plugin to evaluate outside of a render context:

      VolumetricEvaluationFuncs->init() to prepare the volumetric handlers to be
                                        used for rendering
                                        This will call each handler's "init" callback

      VolumetricEvaluationFuncs->newtime() to obtain flags from the volumetric
                                           handlers and invoke a NEWTIME
                                           notification to get them up to date
                                           with the current scrub time.
	                                   This will call each handler's
                                           "newtime" callback

      Create a ray structure using VRayFuncs->New()

      For each ray to be evaluated for whatever purposes:
        VRayFuncs->Init()                     the ray with custom parameters
	VolumetricEvaluationFuncs->evaluate() the ray to figure each volumetric
                                              handler's contribution to the samples
	VRayFuncs->Flatten()                  the ray to obtain colors and
                                              color opacities for that ray

        VRayFuncs->Destroy()                  the ray when done with it.

        VolumetricEvaluationFuncs->cleanUp()  to notify a render finishing to
                                              each volumetric handler.
	                                      This will call each handler's
                                              "cleanup" callback              }

  PLWVolumetricEvaluationFuncs = ^TLWVolumetricEvaluationFuncs ;
  TLWVolumetricEvaluationFuncs = record
    // Prepare the volumetric handlers for being evaluated.
    // pass slot of 0 to process all volumetric servers,
    // otherwise pass specific 1-based slot index of desired server
    Init    : procedure
              (        Slot           : UInt32          ;
                       LWINIT_context : Integer         ) ;
    // Syncronize the volumetric handlers with current Layout time.
    // pass slot of 0 to process all volumetric servers,
    // otherwise pass specific 1-based slot index of desired server
    Newtime : procedure
              (        Slot           : UInt32          ) ;
    // send the ray through to each volumetric handler for evaluation
    // pass slot of 0 to process all volumetric servers,
    // otherwise pass specific 1-based slot index of desired server
    Evalute : function
              (        Slot           : UInt32          ;
                       Ray            : PLWVolumeAccess ;
                       LWVOLF_raytype : Word            ) : Double ;
    // Cleanup the volumetric handlers when done being evaluated.
    // pass slot of 0 to process all volumetric servers,
    // otherwise pass specific 1-based slot index of desired server
    Cleanup : procedure
              (        Slot           : UInt32          ) ;
  end;

implementation

end.
